package com.daji.stream;

import org.junit.jupiter.api.Test;

import java.util.*;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;


class StreamTests {


    /**
     * Filter Test + forEach Test
     * 测试Filter的基本用法
     * 测试ForEach的基本用法
     */
    @Test
    void test1() {
        ArrayList<UserPojo> users = new ArrayList<>();
        users.add(new UserPojo(1, "lbw", "山东省青岛市", 19));
        users.add(new UserPojo(2, "lbw2", "山东省济南市", 20));
        users.add(new UserPojo(3, "lbw3", "北京市", 22));
        users.add(new UserPojo(4, "lbw4", "上海市", 23));
        //第一步：使用filter过滤集合中每个元素的age<21的值
        users.stream().filter(perUser -> perUser.getAge() < 21).forEach(
                perUser -> {
                    //第二步：使用filter过滤集合中每个元素的age<21的值
                    String newAddress = perUser.getAddress() + "新增一个区";
                    System.out.println(newAddress);
                });
    }

    /**
     * Map Test
     * 测试Map的基本用法
     */
    @Test
    void test5() {
        ArrayList<UserPojo> users = new ArrayList<>();
        users.add(new UserPojo(1, "lbw", "山东省青岛市", 19));
        users.add(new UserPojo(2, "lbw2", "山东省济南市", 20));
        users.add(new UserPojo(3, "lbw3", "北京市", 22));
        users.add(new UserPojo(4, "lbw4", "上海市", 23));
        //第一步：使用Map将流中元素转换为String格式
        users.stream().map(new Function<UserPojo, String>() {
            @Override
            public String apply(UserPojo userPojo) {
                return userPojo.getAddress();
            } // 第二步：遍历打印流中元素
        }).forEach(str -> System.out.println(str));
        /*
            最终输出结果：
            山东省青岛市
            山东省济南市
            北京市
            上海市
        */
    }

    /**
     * Sorted Test
     * 测试Sorted的基本用法
     */
    @Test
    void test6() {
        ArrayList<UserPojo> users = new ArrayList<>();
        users.add(new UserPojo(1, "lbw", "山东省青岛市", 19));
        users.add(new UserPojo(2, "lbw2", "山东省济南市", 20));
        users.add(new UserPojo(3, "lbw3", "北京市", 22));
        users.add(new UserPojo(4, "lbw4", "上海市", 23));
        users.stream().sorted().forEach(str -> System.out.println(str));
        //也可以使用带参的sorted：
        //上面的代码等价于：
        users.stream().sorted(new Comparator<UserPojo>() {
            @Override
            public int compare(UserPojo o1, UserPojo o2) {
                return o2.getAge()-o1.getAge();
            }
        }).forEach(str -> System.out.println(str));
    }

    /**
     * 测试将HashMap转换为Set
     */
    @Test
    void test2(){
        HashMap<String, UserPojo> userPojoHashMap = new HashMap<>();
        userPojoHashMap.put("1",new UserPojo(1, "lbw", "山东省青岛市", 19));
        userPojoHashMap.put("2",new UserPojo(2, "lbw2", "山东省青岛市2", 19));
        userPojoHashMap.put("3",new UserPojo(3, "lbw3", "山东省青岛市3", 19));

        //使用keySet，获取原Map中key值的集合
        Set<String> strings = userPojoHashMap.keySet();
        //打印原Map的所有key：
        System.out.println(strings);
        //使用entrySet，获取原Map中 key-value值的集合
        Set<Map.Entry<String, UserPojo>> entries = userPojoHashMap.entrySet();
        for (Map.Entry<String, UserPojo> entry : entries) {
            System.out.println("转换后单列集合可以获取原Map的每一个key："+entry.getKey());
            System.out.println("转换后单列集合可以获取原Map的每一个value："+entry.getValue());
        }
    }

    /**
     * 演示Set的特性：无重复元素
     * 添加了3个元素，但是只输出两个
     */
    @Test
    void test3(){
        HashSet<UserPojo> userPojos = new HashSet<>();
        userPojos.add(new UserPojo(1, "lbw", "山东省青岛市", 19));
        userPojos.add(new UserPojo(1, "lbw", "山东省青岛市2", 19));
        userPojos.add(new UserPojo(1, "lbw", "山东省青岛市", 19));
        for (UserPojo userPojo : userPojos) {
            System.out.println(userPojo);
        }
    }

    /**
     * Collect Test
     * 测试流转化为单列集合（List，Set）
     */
    @Test
    void test7() {
        ArrayList<UserPojo> users = new ArrayList<>();
        users.add(new UserPojo(1, "lbw", "山东省青岛市", 19));
        users.add(new UserPojo(2, "lbw2", "山东省济南市", 20));
        users.add(new UserPojo(3, "lbw3", "北京市", 22));
        users.add(new UserPojo(4, "lbw4", "上海市", 23));
        //1、转化为List
        List<UserPojo> collect = users.stream()
                .filter(perUser -> perUser.getAge() < 21)
                .collect(Collectors.toList());
        //2.转化为Set
        Set<UserPojo> collect1 = users.stream()
                .filter(perUser -> perUser.getAge() < 21)
                .collect(Collectors.toSet());
        System.out.println("over");

    }

    /**
     * Collect Test
     * 测试流转化为双列集合Map
     */
    @Test
    void test8() {
        ArrayList<UserPojo> users = new ArrayList<>();
        users.add(new UserPojo(1, "lbw", "山东省青岛市", 19));
        users.add(new UserPojo(2, "lbw2", "山东省济南市", 20));
        users.add(new UserPojo(3, "lbw3", "北京市", 22));
        users.add(new UserPojo(4, "lbw4", "上海市", 23));
        //1、转化为map（目标：转换成age为键，name为值的map）
        Map<Integer, String> collect = users.stream()
                .filter(perUser -> perUser.getAge() < 21)
                .collect(Collectors.toMap(
                        // 入参1：键的映射
                        new Function<UserPojo, Integer>() {
                            @Override
                            public Integer apply(UserPojo userPojo) {
                                return userPojo.getAge();
                            }
                        },
                        // 入参2：值的映射
                        new Function<UserPojo, String>() {
                            @Override
                            public String apply(UserPojo userPojo) {
                                return userPojo.getName();
                            }
                        }
                ));
        System.out.println("over");

    }

    /**
     * Reduce Test
     * 测试Reduce的基本用法
     */
    @Test
    void test10() {
        ArrayList<UserPojo> users = new ArrayList<>();
        users.add(new UserPojo(1, "lbw", "山东省青岛市", 19));
        users.add(new UserPojo(2, "lbw2", "山东省济南市", 20));
        users.add(new UserPojo(3, "lbw3", "北京市", 22));
        users.add(new UserPojo(4, "lbw4", "上海市", 23));

        Integer sum = users.stream()
                //第一步：使用Map将流中元素只取age
                .map(userPojo -> userPojo.getAge())
                //第二步：使用reduce获取age相加后的结果
                //从0开始累加。注意第一个形参
                .reduce(0, new BinaryOperator<Integer>() {
                    @Override
                    public Integer apply(Integer result, Integer perElement) {
                        return result + perElement;
                    }
                });
        System.out.println(sum);
    }


    /**
     * Reduce Test
     * 测试Reduce的基本用法2(求最大值)
     */
    @Test
    void test11() {
        ArrayList<UserPojo> users = new ArrayList<>();
        users.add(new UserPojo(1, "lbw", "山东省青岛市", 19));
        users.add(new UserPojo(2, "lbw2", "山东省济南市", 20));
        users.add(new UserPojo(3, "lbw3", "北京市", 22));
        users.add(new UserPojo(4, "lbw4", "上海市", 23));

        Integer sum = users.stream()
                //第一步：使用Map将流中元素只取age
                .map(userPojo -> userPojo.getAge())
                //第二步：使用reduce获取年龄的最值
                //注意第一个形参,选择的是Integer的最小值。以确保不会出错
                .reduce(Integer.MIN_VALUE, new BinaryOperator<Integer>() {
                    @Override
                    public Integer apply(Integer result, Integer perElement) {
                        return result > perElement ? result : perElement;
                    }
                });
        System.out.println(sum);
    }


    /**
     * Parallel Test
     * 测试并行流的基本用法
     */
    @Test
    void test13() {
        //1、不使用并行流的过滤
        Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9);
        List<Integer> collect = integerStream
                .filter(num -> num > 4)
                .collect(Collectors.toList());
        //2、假设数据量很大，可以使用并行流
        Stream<Integer> integerStream2 = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9);
        List<Integer> collect2 = integerStream2
                .parallel() //转换成并行流
                .filter(num -> num > 4)
                .collect(Collectors.toList());

    }

}
